package com.sir.tao.carhire.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sir.tao.carhire.entity.table.CarEntity;
import com.sir.tao.carhire.entity.table.ContractEntity;
import com.sir.tao.carhire.entity.table.UserEntity;
import com.sir.tao.carhire.entity.vo.HeaderVo;
import com.sir.tao.carhire.entity.vo.Vo;
import com.sir.tao.carhire.service.CarService;
import com.sir.tao.carhire.service.ContractService;
import com.sir.tao.carhire.service.ManagementService;
import com.sir.tao.carhire.service.UserService;
import com.sir.tao.carhire.util.DateUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ManagementServiceImpl implements ManagementService {

    @Resource
    private ContractService contractService;
    @Resource
    private UserService userService;
    @Resource
    private CarService carService;
    private static final  int ONE_MONTH_DAY = 30;
    private static final int ONE_YEAR_MONTH=12;
    private Vo trVo;
    @Override
    public HeaderVo getHeader(Vo vo) {
        HeaderVo headerVo = new HeaderVo();

        int orderNumber = getOrderNumber(vo).size();
        headerVo.setTotalOrder(orderNumber);

        int totalPerson = getPersonNumber(vo).size();
        headerVo.setTotalPerson(totalPerson);

        BigDecimal totalTransactions = getTotalTransactions(vo);
        headerVo.setTotalTransactions(totalTransactions);

        BigDecimal netIncome = headerVo.getTotalTransactions();
        headerVo.setNetIncome(netIncome);
        return headerVo;
    }




    private BigDecimal getTotalTransactions(Vo vo) {
        List<ContractEntity> list = getOrderNumber(vo);
        Map<String,BigDecimal> carPrice = carService.list().stream().collect(Collectors.toMap(CarEntity::getId,CarEntity::getPrice));
        return list.stream()
                .map(contractEntity -> {
                    BigDecimal b = carPrice.get(contractEntity.getCarId());
                    if (Objects.isNull(b)){
                        return new BigDecimal(0);
                    }
                    return b;
                })
                .reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
    }

    private List<UserEntity> getPersonNumber(Vo vo) {

        return userService.list(new LambdaQueryWrapper<UserEntity>()
                .ge(!Objects.isNull(vo.getStartTime()),UserEntity::getCreateTime,vo.getStartTime())
                .le(!Objects.isNull(vo.getEndTime()),UserEntity::getCreateTime,vo.getEndTime())
        );

    }

    private List<ContractEntity> getOrderNumber(Vo vo) {

        return contractService.list(new LambdaQueryWrapper<ContractEntity>()

                .ge(!Objects.isNull(vo.getStartTime()),ContractEntity::getCreateTime,vo.getStartTime())
                .le(!Objects.isNull(vo.getEndTime()),ContractEntity::getCreateTime,vo.getEndTime())
                .eq(ContractEntity::getStatus,5)
        );

    }

    @Override
    public Map<String, TreeMap<String, BigDecimal>> getBody(Vo vo) {

        int differMonth = DateUtil.getDifMonth(vo.getStartTime(),vo.getEndTime());
        int differDay = DateUtil.differDay(vo.getStartTime(),vo.getEndTime());

        boolean b = differMonth==1&&differDay<ONE_MONTH_DAY;

        List<UserEntity> userList = getPersonNumber(vo);
        List<ContractEntity> contractEntityList = getOrderNumber(vo);

        if(differMonth==0 || b){
            trVo = vo;
            //按天进行展示
//            return null;
            return doDay(userList,contractEntityList);
        }else if(differMonth>1 && differMonth<=ONE_YEAR_MONTH){
            trVo = vo;
            //按月进行展示//总交易额
            return doMonth(userList,contractEntityList);
//            return null;
        }else {
            trVo = vo;
            //按年进行展示//总交易额
            return doYear(userList,contractEntityList);
//            return null;
        }
    }

    private Map<String, TreeMap<String, BigDecimal>> doYear(List<UserEntity> userList, List<ContractEntity> contractEntityList) {
        return getListTreeMap(userList, contractEntityList,3);
    }

    private Map<String, TreeMap<String, BigDecimal>> doMonth(List<UserEntity> userList, List<ContractEntity> contractEntityList) {
        return getListTreeMap(userList, contractEntityList,2);
    }

    private Map<String, TreeMap<String, BigDecimal>> doDay(List<UserEntity> userList, List<ContractEntity> contractEntityList) {
        return getListTreeMap(userList, contractEntityList,1);
    }

    private Map<String, TreeMap<String, BigDecimal>> getListTreeMap(List<UserEntity> userList, List<ContractEntity> contractEntityList, int type) {
        Map<String,TreeMap<String, BigDecimal>> list = new HashMap<>();
        TreeMap<String,BigDecimal> recommendMap = getRecommendMap(contractEntityList,type);
        list.put("finance",recommendMap);

        TreeMap<String,BigDecimal> userTree = getUserTree(userList,type);
        list.put("userAdd",userTree);
        TreeMap<String,BigDecimal> orderRecommend = getOrderRecommendTree(contractEntityList,type);
        list.put("contractAdd",orderRecommend);

        return list;

    }

    private TreeMap<String, BigDecimal> getOrderRecommendTree(List<ContractEntity> contractEntityList, int type) {
        Map<Date,List<ContractEntity>> users = contractEntityList
                .stream()
                .peek(userEntity -> {
                    switch (type){
                        case 1: userEntity.setCreateTime(getDay(userEntity.getCreateTime()));break;
                        case 2: userEntity.setCreateTime(getMonth(userEntity.getCreateTime()));break;
                        case 3: userEntity.setCreateTime(getYear(userEntity.getCreateTime()));break;
                        default: break;
                    }                })
                .collect(Collectors.groupingBy(ContractEntity::getCreateTime));
        TreeMap<String, BigDecimal> userMap = doTreeMap(trVo,type);
        for(Map.Entry<Date, List<ContractEntity>> entry : users.entrySet()){
            int date =0 ;
            switch (type){
                case 1:date = DateUtil.getDay(entry.getKey());break;
                case 2:date = DateUtil.getMonth(entry.getKey());break;
                case 3:date = DateUtil.getYear(entry.getKey());break;
                default:break;
            }
            int userNumber = entry.getValue().size();
            userMap.put("a"+date,new BigDecimal(userNumber));
        }
        return userMap;
    }

    private TreeMap<String, BigDecimal> getUserTree(List<UserEntity> userList, int type) {
        Map<Date,List<UserEntity>> users = userList
                .stream()
                .peek(userEntity -> {
                    switch (type){
                        case 1: userEntity.setCreateTime(getDay(userEntity.getCreateTime()));break;
                        case 2: userEntity.setCreateTime(getMonth(userEntity.getCreateTime()));break;
                        case 3: userEntity.setCreateTime(getYear(userEntity.getCreateTime()));break;
                        default: break;
                    }                })
                .collect(Collectors.groupingBy(UserEntity::getCreateTime));
        TreeMap<String, BigDecimal> userMap = doTreeMap(trVo,type);
        for(Map.Entry<Date, List<UserEntity>> entry : users.entrySet()){
            int date =0 ;
            switch (type){
                case 1:date = DateUtil.getDay(entry.getKey());break;
                case 2:date = DateUtil.getMonth(entry.getKey());break;
                case 3:date = DateUtil.getYear(entry.getKey());break;
                default:break;
            }
            int userNumber = entry.getValue().size();
            userMap.put("a"+date,new BigDecimal(userNumber));
        }
        return userMap;
    }

    private TreeMap<String, BigDecimal> getRecommendMap(List<ContractEntity> contractEntityList, int type) {

        Map<Date,List<ContractEntity>> malls = contractEntityList
                .stream()
                .peek(contractEntity -> {
                    switch (type){
                        case 1: contractEntity.setCreateTime(getDay(contractEntity.getCreateTime()));break;
                        case 2: contractEntity.setCreateTime(getMonth(contractEntity.getCreateTime()));break;
                        case 3: contractEntity.setCreateTime(getYear(contractEntity.getCreateTime()));break;
                        default: break;
                    }                })
                .collect(Collectors.groupingBy(ContractEntity::getCreateTime));
        TreeMap<String, BigDecimal> treeMap = doTreeMap(trVo,type);

        for(Map.Entry<Date, List<ContractEntity>> entry : malls.entrySet()){
            int date =0 ;
            switch (type){
                case 1: date = DateUtil.getDay(entry.getKey());break;
                case 2: date = DateUtil.getMonth(entry.getKey());break;
                case 3: date = DateUtil.getYear(entry.getKey());break;
                default: break;
            }
            BigDecimal bigDecimal = recommendListToBigDecimal(entry.getValue());
            if (treeMap.containsKey("a"+date)){
                bigDecimal = bigDecimal.add(treeMap.get("a"+date));
            }
            treeMap.put("a"+date,bigDecimal.setScale(2, BigDecimal.ROUND_DOWN));
        }
        return treeMap;
    }

    private BigDecimal recommendListToBigDecimal(List<ContractEntity> value) {
        //如果没有推荐订单，则直接返回
        if (value.size()==0){
            return new BigDecimal(0);
        }
        Map<String,BigDecimal> carPrice = carService.list().stream().collect(Collectors.toMap(CarEntity::getId,CarEntity::getPrice));

        return value.stream()
                .map(contractEntity -> {
                    BigDecimal b = carPrice.get(contractEntity.getCarId());
                    if (Objects.isNull(b)){
                        return new BigDecimal(0);
                    }else {
                        return b;
                    }
                })
                .reduce(BigDecimal::add).orElse(BigDecimal.ZERO);


    }

    private TreeMap<String, BigDecimal> doTreeMap(Vo vo, int type) {

        int start = 0;
        int end = 0;
        int number = 0;
        switch (type){
            case 1:
                number = ONE_MONTH_DAY;
                start = DateUtil.getDay(vo.getStartTime());
                end = DateUtil.getDay(vo.getEndTime());break;
            case 2:
                number = ONE_YEAR_MONTH;
                start = DateUtil.getMonth(vo.getStartTime());
                end = DateUtil.getMonth(vo.getEndTime());break;
            case 3:
                start = DateUtil.getYear(vo.getStartTime());
                end = DateUtil.getYear(vo.getEndTime());break;
            default: break;
        }
        if (end>start){
            return getNormalMap();
        }else {
            return getOtherMap(end,number);
        }
    }

    private TreeMap<String, BigDecimal> getOtherMap(int end, int number) {
        return  new TreeMap<>((o1, o2) -> {
            int d1 = Integer.parseInt(o1.substring(1));
            int d2 = Integer.parseInt(o2.substring(1));
            if (d1<=end){ d1 += number; }
            if (d2<=end){ d2 += number; }
            return Integer.compare(d1, d2);
        });
    }

    private TreeMap<String, BigDecimal> getNormalMap() {
        return  new TreeMap<>((o1, o2) -> {
            int d1 = Integer.parseInt(o1.substring(1));
            int d2 = Integer.parseInt(o2.substring(1));
            return Integer.compare(d1, d2);
        });
    }


    private Date getYear(Date createTime) {
        return new Date(DateUtil.getTodayTimeFrame(createTime)[0]);
    }

    private Date getMonth(Date createTime) {
        return new Date(DateUtil.getTodayTimeFrame(createTime)[0]);
    }

    private Date getDay(Date createTime) {
        return new Date(DateUtil.getTodayTimeFrame(createTime)[0]);
    }


}
